package com.spm.librarianmanagersystem.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.spm.librarianmanagersystem.mapper.*;
import com.spm.librarianmanagersystem.pojo.Borrow;
import com.spm.librarianmanagersystem.pojo.Fine;
import com.spm.librarianmanagersystem.pojo.Member;
import com.spm.librarianmanagersystem.service.BorrowService;
import com.spm.librarianmanagersystem.utils.SnowFlakeIDUtil;
import com.spm.librarianmanagersystem.utils.UserContextHolder;
import com.spm.librarianmanagersystem.vo.BookLocation;
import com.spm.librarianmanagersystem.vo.borrowDetail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Service("BorrowService")
public class BorrowServiceImpl implements BorrowService {
    @Autowired
    private BorrowMapper bm;
    @Autowired
    private FineMapper fm;
    @Autowired
    MemberMapper memberMapper;
    @Autowired
    BookMapper bookMapper;
    @Autowired
    BookDetailMapper bookDetailMapper;
    @Autowired
    ReservationMapper reservationMapper;

    /**
     * 用户借书服务
     * @param currentUserId
     * @param borrowRequest
     */
    @Override
    @Transactional
    public Integer borrowBook(String currentUserId, JSONObject borrowRequest) throws Exception {

        // 获取借书人ID
        Member member = memberMapper.getMemberByID(currentUserId);
        //System.out.println("借阅人的id!!!" + member.getName() + "reputationscore" + member.getReputationScore());

        Integer bookId = Integer.valueOf((String) borrowRequest.get("book_id"));
        String ISBN = (String) borrowRequest.get("ISBN");

        //获取信誉值进而计算借阅时间
        Integer reputation_score = member.getReputationScore();
        System.out.println("user:" + member.getName() + "reputation:" + member.getReputationScore());
        int borrow_days = reputation_score <=100 ? 10 : 10 + (reputation_score - 100) / 10;
        System.out.println(borrow_days);
        // 定义十天借书时间
        long borrowStartTime = System.currentTimeMillis();
        long dueTimeLong = borrowStartTime + borrow_days * 24 * 60 * 60 * 1000L;
        Date borrowStartDate = new Date(borrowStartTime);
        Date dueTime = new Date(dueTimeLong);
        System.out.println(borrowStartDate);
        System.out.println(dueTime);

        // 生成借书ID
        SnowFlakeIDUtil snowFlakeIDUtil = new SnowFlakeIDUtil();
        Integer borrowId = (int) snowFlakeIDUtil.nextId();
        // 可能存在越界的情况，需要加绝对值来限制
        borrowId = Math.abs(borrowId);
        borrowDetail borrow = new borrowDetail(borrowId, Long.valueOf(member.getUserId()), bookId, ISBN, dueTime, borrowStartDate,0, 0, new java.util.Date(), 0.0);

        // 判断该书本是否可借（可操作数量小于当前所有可借书数量）
        List<BookLocation> bookLocations = bookDetailMapper.searchBookLocationByISBN(ISBN);

        // 检查书库中是否有这本书
        if (bookLocations.size() == 0) {
            throw new Exception("当前是书籍不存在请检查！");
        }

        int canLend = bookLocations.size();
        for (BookLocation bookLocation : bookLocations) {
            if (bookLocation.getStatus().equals("1"))
                canLend--;
        }
        List<String> bookUser = reservationMapper.getBookReservations(ISBN);
//        canLend -= bookUser.size();
//        System.out.println(canLend);
//        System.out.println(currentUserId);
        Integer UserID = memberMapper.getUserIDByID(currentUserId);
//        System.out.println(UserID);
//        for (String user : bookUser) {
//            if (String.valueOf(UserID).equals(user)) {
//                canLend = 1;
//                break;
//            }
//        }
//        if (canLend <= 0)
//            throw new Exception("当前是书籍借阅/预约数量已经达到上限！");

        // 判断是否存在未付款订单
        List<Fine> fineList = fm.getFineList(currentUserId);
        fineList.removeIf(fine -> fine.getAmount() == 0);
        if (!fineList.isEmpty())
            throw new Exception("当前用户有未支付的罚款！");

        // 检查在借书籍数目，使用还书字段是否为空判断
        List<Borrow> borrowingList = bm.getBorrowingList(currentUserId);
        int count = 0;
        for (Borrow borrowRecord : borrowingList) {
            if (borrowRecord.getActReturnTime() == null) {
                System.out.println(borrowRecord);
                if (ISBN.equals(borrowRecord.getISBN()))
                    throw new Exception("当前用户同时借了同一本书！");
                count ++;
            }
        }

        // 超出5本不能再借书
        if (count >= 5)
            throw new Exception("当前用户可借书目达到上限！");

        // 捕获操作数据库异常
        try {
            bm.borrowBook(borrow);
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("借书异常！");
        }

        try {
            bookMapper.updateBookLocation(ISBN, bookId);
            reservationMapper.updateReservationForFinish(UserID, ISBN);
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("更新书本/预约信息异常！");
        }

        return borrowId;
    }

    @Override
    public JSONArray getBorrowingList(String currentUserId) {
        List<Borrow> borrowingList = bm.getBorrowingList(currentUserId);
        JSONArray array = new JSONArray();
        for (Borrow b : borrowingList) {
            Double fineByBorrowNum = fm.getFineByBorrowNum(b.getBorrowingNumber());
            Integer fineStatus = fm.getFineStatusByBorrowNum(b.getBorrowingNumber());
            JSONObject object = new JSONObject();
            object.put("borrowing_id", b.getBorrowingNumber());
            object.put("book_id", b.getBookId());
            object.put("ISBN", b.getISBN());
            object.put("borrow_date", b.getBorrowStartTime());
            object.put("due_date", b.getDueTime());
            if(b.getDueTime().before(new Date())){
                object.put("overdue",1);
            }
            else{
                object.put("overdue",0);
            }
            object.put("fine",fineByBorrowNum);
            object.put("fine_status",fineStatus);
            array.add(object);
        }
        return array;
    }

    @Override
    public JSONArray getBorrowHistory(String currentUserId) {
        List<Borrow> borrowingList = bm.getBorrowHistory(currentUserId);
        JSONArray array = new JSONArray();
        for (Borrow b : borrowingList) {
            Double fineByBorrowNum = fm.getFineByBorrowNum(b.getBorrowingNumber());
            Integer fineStatus = fm.getFineStatusByBorrowNum(b.getBorrowingNumber());
            JSONObject object = new JSONObject();
            object.put("borrowing_id", b.getBorrowingNumber());
            object.put("book_id", b.getBookId());
            object.put("ISBN", b.getISBN());
            object.put("status", b.getStatus());
            object.put("borrow_time", b.getBorrowStartTime());
            object.put("due_time", b.getDueTime());
            object.put("return_time", b.getActReturnTime());
            object.put("fine",fineByBorrowNum);
            object.put("fine_status",fineStatus);
            array.add(object);
        }
        return array;
    }

    @Override
    public JSONObject getBorrowRecordDetail(Integer borrowingId) {
        Borrow borrowRecord = bm.getBorrowRecordByNumber(borrowingId);
        Double fineByBorrowNum = fm.getFineByBorrowNum(borrowingId);
        Integer fineStatus = fm.getFineStatusByBorrowNum(borrowingId);
        JSONObject object = new JSONObject();
        object.put("borrowing_id", borrowingId);
        object.put("book_id", borrowRecord.getBookId());
        object.put("ISBN", borrowRecord.getISBN());
        object.put("status", borrowRecord.getStatus());
        object.put("borrow_time", borrowRecord.getBorrowStartTime());
        object.put("due_time", borrowRecord.getDueTime());
        object.put("return_time", borrowRecord.getActReturnTime());
        object.put("fine",fineByBorrowNum);
        object.put("fine_status",fineStatus);
        return object;
    }

    @Override
    public Boolean updateScore(Integer borrowingId, Double score) {
        Boolean status = bm.updateScore(borrowingId, score);
        return status;
    }


}
